package com.xiaoyu.cloud.interceptor;


import com.xiaoyu.cloud.core.constants.ComConst;
import com.xiaoyu.common.core.currentUser.TransmittableThreadLocalRequestHeaders;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @author zgb
 * @desc 传递请求头:要求hystrix使用信号量模式 （同一个线程下的请求转发）
 * @date 2022-05-30 15:38:58
 */
//RequestInterceptor是feign的拦截器
//去掉@Configuration则为局部配置
//配置@Component或@Service 或 @Configuration 就可以将该配置注入spring容器中, 即可实现全局配置, 从而该项目中的所有FeignClient的feign接口都可以使用该配置.
@Configuration
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        String traceId = MDC.get("traceId");
        requestTemplate.header("traceId", traceId);
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            //获取请求
            HttpServletRequest request = attributes.getRequest();
            long currentThreadId = Thread.currentThread().getId();
            log.info("VersionGrayGlobalFilter.currentThreadId:" + currentThreadId);
            String requestedSessionId = request.getRequestedSessionId();
            log.info("VersionGrayGlobalFilter.requestedSessionId:" + requestedSessionId);

            if (request != null) {
                Enumeration<String> headerNames = request.getHeaderNames();
                if (headerNames != null) {
                    while (headerNames.hasMoreElements()) {
                        String name = headerNames.nextElement();
                        String values = request.getHeader(name);
                        //头信息传递
                        //feign 使用的是线程池模式，当开启熔断的时候，feign 所在的服务端不在同一个线程，这时attributes取到的将会是空值
                        //解决：改用信号量模式
                        //feign底层是requestTemplate
                        requestTemplate.header(name, values);
                    }
                }
            }
            // 微服务之间传递的唯一标识,区分大小写所以通过httpServletRequest获取
            if (request.getHeader(ComConst.FEIGN_REQUEST_ID_KEY) == null) {
                requestTemplate.header(ComConst.FEIGN_REQUEST_ID_KEY, traceId);
            }

        }

        Map<String, Collection<String>> headers1 = requestTemplate.headers();
        Map<String, List<String>> map = new HashMap<>();
        headers1.forEach((k, v) -> {
            List<String> list = new ArrayList<>();
            list.addAll(v);
            map.put(k, list);
        });
        MultiValueMap<String, String> headers2= CollectionUtils.toMultiValueMap(map);
        HttpHeaders headers = new HttpHeaders(headers2);
        //线程安全上下文
        TransmittableThreadLocalRequestHeaders.set(headers);
    }
}
